/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "GY_DiagramScene.h"

#include <QGraphicsItem>
#include <QGraphicsSceneMouseEvent>
#include <QTextCursor>
#include <QDebug>
#include <QKeyEvent>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QMap>
#include "GY_GraphicsViewBP.h"
#include "GY_PopupMenu.h"
#include "GY_ValuePanel.h"
//! [0]
GY_DiagramScene::GY_DiagramScene(QMenu *itemMenu, QObject *parent)
    : QGraphicsScene(parent)
{
    myItemMenu = itemMenu;
    myMode = MoveItem;
    myItemType = GY_DiagramItem::Step;
    line     = nullptr;
    textItem = nullptr;
    mPort    = nullptr;
//    myItemColor = Qt::white;
    myTextColor = Qt::black;
    myLineColor = Qt::black;

    mScale = 1;



    //pMenu = new PopupMenu();//无法设置parent


}
//! [0]

//! [1]
void GY_DiagramScene::setLineColor(const QColor &color)
{
    myLineColor = color;
    if (isItemChange(GY_Arrow::Type)) {
        GY_Arrow *item = qgraphicsitem_cast<GY_Arrow *>(selectedItems().first());
        item->setColor(myLineColor);
        update();
    }
}
//! [1]

//! [2]
void GY_DiagramScene::setTextColor(const QColor &color)
{
    myTextColor = color;
    if (isItemChange(GY_DiagramTextItem::Type)) {
        GY_DiagramTextItem *item = qgraphicsitem_cast<GY_DiagramTextItem *>(selectedItems().first());
        item->setDefaultTextColor(myTextColor);
    }
}
//! [2]

//! [3]
void GY_DiagramScene::setItemColor(const QColor &color)
{
    myItemColor = color;
    if (isItemChange(GY_DiagramItem::Type)) {
        GY_DiagramItem *item = qgraphicsitem_cast<GY_DiagramItem *>(selectedItems().first());
        item->setBrush(myItemColor);
    }
}

void GY_DiagramScene::setItemTextColor(const QColor &color)
{
    myItemTextColor = color;
}

void GY_DiagramScene::setItemFontPixelSize(int value)
{

    myItemFontPixelSize = value;

}
//! [3]

//! [4]
void GY_DiagramScene::setFont(const QFont &font)
{
    myFont = font;

    if (isItemChange(GY_DiagramTextItem::Type)) {
        QGraphicsTextItem *item = qgraphicsitem_cast<GY_DiagramTextItem *>(selectedItems().first());
        //At this point the selection can change so the first selected item might not be a DiagramTextItem
        if (item)
            item->setFont(myFont);
    }
}
//! [4]

void GY_DiagramScene::setMode(Mode mode)
{
    myMode = mode;
}

void GY_DiagramScene::setItemType(GY_DiagramItem::DiagramType type)
{
    myItemType = type;
}

//! [5]
void GY_DiagramScene::editorLostFocus(GY_DiagramTextItem *item)
{
    QTextCursor cursor = item->textCursor();
    cursor.clearSelection();
    item->setTextCursor(cursor);

    if (item->toPlainText().isEmpty()) {
        removeItem(item);
        item->deleteLater();
    }
}
//! [5]

void GY_DiagramScene::SlotInsertItem(QString str, GY_DiagramScene::Mode mode){
    setMode(mode);
    //setItemType(DiagramItem::Step);

    GY_DiagramItem *item;
    QJsonParseError e;
    QJsonDocument doc;
    if(InsertItem==myMode) {

        item = new GY_DiagramItem(myItemType, myItemMenu,str, myItemTextColor, myItemFontPixelSize);
        item->setBrush(myItemColor);

        if(item->pos().isNull()){
            item->setPos(addItemAtPoint);
        }

        addItem(item);


        if(line){  //自动连线到新item的第一个槽
            switch (line->GetLineType()) {
            case GY_Arrow::proc:
                if(line->startPort()){
                    if(item->GetPortsProcI().size()){
                        line->SetEndPort(item->GetPortsProcI().first());
                        line->endPort()->SetColor(line->startPort()->GetColor());
                    }
                }
                else if(line->endPort()){
                    if(item->GetPortsProcO().size()){
                        line->SetStartPort(item->GetPortsProcO().first());
                        line->startPort()->SetColor(line->endPort()->GetColor());
                    }
                }
                break;
            case GY_Arrow::data:
                if(line->startPort()){
                    if(item->GetPortsDataI().size()){
                        line->SetEndPort(item->GetPortsDataI().first());
                        line->endPort()->SetColor(line->startPort()->GetColor());
                    }
                }
                else if(line->endPort()){
                    if(item->GetPortsDataO().size()){
                        line->SetStartPort(item->GetPortsDataO().first());
                        line->startPort()->SetColor(line->endPort()->GetColor());
                    }
                }
                line->endPort()->SetValue("");  //参数连线后需要重置槽的参数值及更新参数面板值
                break;
            default:
                break;
            }
            line->startPort()->SetLineCount(1);
            line->endPort()->SetLineCount(1);  //拖出来的线创建的item无可连接的槽时错误
            ((GY_DiagramItem*)line->startPort()->parentItem())->addArrow(line);
            ((GY_DiagramItem*)line->endPort()->parentItem())->addArrow(line);
            line->setZValue(-1000.0);
            line->updatePosition();

            line = nullptr;  //准备画新线
        }
    }
    else if(InsertLine==myMode) {

        //doc.fromJson(str.toUtf8(),&e);  //错误
        doc = QJsonDocument::fromJson(str.toUtf8(),&e);
        if(e.error == QJsonParseError::NoError){
            //qDebug()<<doc.isObject();  //
            QJsonObject obj = doc.object();

            GY_DiagramItem* from = nullptr;
            for(QGraphicsItem* item : items()){
                if(item->type()==GY_DiagramItem::Type){

                    if(((GY_DiagramItem*)item)->GetUuid()==obj["from"].toString()){
                        from = (GY_DiagramItem*)item;
                        break;
                    }
                }
            }

            GY_DiagramItem* to = nullptr;
            for(QGraphicsItem* item : items()){
                if(item->type()==GY_DiagramItem::Type){

                    if(((GY_DiagramItem*)item)->GetUuid()==obj["to"].toString()){
                        to = (GY_DiagramItem*)item;
                        break;
                    }
                }
            }

            if(from && to){
                GY_PortItem* portO = nullptr;
                GY_PortItem* portI = nullptr;

                if(obj.contains("PO")){
                    setLineType(GY_Arrow::proc);
                    for(GY_PortItem* port:from->GetPortsProcO()){
                        if(port->GetName() == obj["PO"].toString()){
                            portO = port;
                            break;
                        }
                    }
                    for(GY_PortItem* port:to->GetPortsProcI()){
                        if(port->GetName() == obj["PI"].toString()){
                            portI = port;
                            break;
                        }
                    }
                }
                else if(obj.contains("DO")){
                    setLineType(GY_Arrow::data);
                    for(GY_PortItem* port:from->GetPortsDataO()){
                        if(port->GetName() == obj["DO"].toString()){
                            portO = port;
                            break;
                        }
                    }

                    for(GY_PortItem* port:to->GetPortsDataI()){
                        if(port->GetName() == obj["DI"].toString()){
                            portI = port;
                            break;
                        }
                    }
                }

                if(portO && portI){
                    line = new GY_Arrow(QLineF(portO->boundingRect().center(),
                                                portI->boundingRect().center()));
                    line->SetLineType(lineType);
                    line->setZValue(-1000.0);
                    line->SetStartPort(portO);
                    line->SetEndPort(portI);
                    line->setColor(line->startPort()->GetColor());
                    line->endPort()->SetColor(line->startPort()->GetColor());
                    line->startPort()->SetLineCount(1);  //qDebug()<<line->startPort()->GetLineCount();
                    line->endPort()->SetLineCount(1);  //qDebug()<<line->endPort()->GetLineCount();
                    from->addArrow(line);
                    to->addArrow(line);
                    addItem(line);
                    update();  //自动刷新没有效果


                    line = nullptr;
                }

            }

        }
    }




    //最后
    setMode(MoveItem);
}

//! [6]
void GY_DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{


    if (mouseEvent->button() != Qt::LeftButton){
        return;
    }
    emit sigHidePopupMenu();

    ((GY_GraphicsViewBP*)this->parent())->HidePanel();

    //判断是否选中PortItem画线
    //qDebug()<<"selectedItems().size()"<<selectedItems().size();  //数据更新比实际慢
    //this->clearSelection();  //影响多选
    QTransform tran;
    QGraphicsItem* item = this->itemAt(mouseEvent->scenePos(),tran);
    if(item){//qDebug()<<item->type();
        //item->setSelected(true);  //影响多选


        //选中线时变化插槽形状，表示线被选中
        if(item->type() == GY_Arrow::Type){
            selLine = ((GY_Arrow*)item);
            if(selLine->startPort()){
                selLine->startPort()->setLinkedBySelLine(true);
                selLine->startPort()->update();  //重绘
            }
            if(selLine->endPort()){
                selLine->endPort()->setLinkedBySelLine(true);
                selLine->endPort()->update();  //重绘
            }
        }
        else{
            if(selLine){
                if(selLine->startPort()){
                    selLine->startPort()->setLinkedBySelLine(false);
                    selLine->startPort()->update();  //重绘
                }
                if(selLine->endPort()){
                    selLine->endPort()->setLinkedBySelLine(false);
                    selLine->endPort()->update();  //重绘
                }

                selLine = nullptr;
            }
        }



        //if(item->type() == PortItem::Type){
        if(item->type() != GY_DiagramItem::Type && item->type() != GY_Arrow::Type){
            //此处PortItem无法判断选中，所以用排除法。当增加item类型时，注意检查item->type()更新判断条件。
            GY_PortItem* port = ((GY_PortItem*)item);
            if(port->GetPortType()!=GY_PortItem::add){
                setMode(GY_DiagramScene::InsertLine);
                setLineType(port->GetPortType()==GY_PortItem::procI||port->GetPortType()==GY_PortItem::procO ? GY_Arrow::proc : GY_Arrow::data);
                setPort(port);

            }else{

                port->moveBy(0,20);  //先于addPort()
                ((GY_DiagramItem*)port->parentItem())->addPort(port->GetAddToType(),port);

                ((GY_GraphicsViewBP*)this->parent())->ShowPanel((GY_DiagramItem*) port->parentItem());

                return;
            }
        }
    }


    if(line){
        removeItem(line);
        delete line;
        line = nullptr;

        setMode(MoveItem);
    }



//    DiagramItem *item;

    switch (myMode) {
    case InsertItem:
//            item = new DiagramItem(myItemType, myItemMenu,"");
//            item->setBrush(myItemColor);
//            addItem(item);
//            item->setPos(mouseEvent->scenePos());
//            //emit itemInserted(item);
//            setMode(DiagramScene::MoveItem);
        break;
//! [6] //! [7]
    case InsertLine:
        //


        line = new GY_Arrow(QLineF(mouseEvent->scenePos(),
                                    mouseEvent->scenePos()));
        addItem(line);
        line->SetLineType(lineType);
        if(GY_PortItem::dataO==mPort->GetPortType() || GY_PortItem::procO==mPort->GetPortType()){
            line->SetStartPort(mPort);
        }
        else {
            line->SetEndPort(mPort);
        }

        line->setColor(mPort->GetColor());



        break;
//! [7] //! [8]
    case InsertText:
        textItem = new GY_DiagramTextItem();
        textItem->setFont(myFont);
        textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
        textItem->setZValue(-1000.0);
        connect(textItem, &GY_DiagramTextItem::lostFocus,
                this, &GY_DiagramScene::editorLostFocus);
        connect(textItem, &GY_DiagramTextItem::selectedChange,
                this, &GY_DiagramScene::itemSelected);
        addItem(textItem);
        textItem->setDefaultTextColor(myTextColor);
        textItem->setPos(mouseEvent->scenePos());
        emit textInserted(textItem);
        break;
//! [8] //! [9]
    default:  //MoveItem

        break;
    }


    QGraphicsScene::mousePressEvent(mouseEvent);
}
//! [9]


void GY_DiagramScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event){
    QTransform tran;
    QGraphicsItem* item = this->itemAt(event->scenePos(),tran);
    if(item){
        if(item->type()==GY_DiagramItem::Type){
            if(((GY_DiagramItem*) item)->diagramType()==GY_DiagramItem::Input
            || ((GY_DiagramItem*) item)->diagramType()==GY_DiagramItem::Step
            || ((GY_DiagramItem*) item)->diagramType()==GY_DiagramItem::Branch){
                ((GY_GraphicsViewBP*)this->parent())->ShowPanel((GY_DiagramItem*) item);
            }
        }
    }

    QGraphicsScene::mouseDoubleClickEvent(event);
}


//! [10]
void GY_DiagramScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{


    if (myMode == InsertLine && line != nullptr) {
        if(!((GY_GraphicsViewBP*)this->parent())->GetMenu()->isVisible()){
            QLineF newLine(line->line().p1(), mouseEvent->scenePos());
            line->setLine(newLine);
        }
    }
    else if (myMode == MoveItem) {
        //更新已画好的线条
        for(QGraphicsItem* item : selectedItems()){
            if(item->type() == GY_DiagramItem::Type){  //非DiagramItem类强制转换崩溃
                GY_DiagramItem *mvItem = qgraphicsitem_cast<GY_DiagramItem *>(item);
                for(GY_Arrow* arrow: mvItem->GetArrows()){
                    arrow->updatePosition();
                    //qDebug()<<arrow->line();
                }
            }
        }


        QGraphicsScene::mouseMoveEvent(mouseEvent);
    }

}


void GY_DiagramScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{



    if (line != nullptr && myMode == InsertLine) {
        QList<QGraphicsItem *> startItems = items(line->line().p1(),Qt::IntersectsItemShape);
        for(QGraphicsItem * item : startItems){
            //qDebug()<<item->type();  //items不包含PortItem
            if(GY_DiagramItem::Type != item->type() && item->type()!=GY_PortItem::Type){
                startItems.removeOne(item);
            }
        }


        QList<QGraphicsItem *> endItems = items(line->line().p2());
        for(QGraphicsItem * item : endItems){
            //qDebug()<<item->type();  //items不包含PortItem
            if(GY_DiagramItem::Type != item->type() && item->type()!=GY_PortItem::Type){
                endItems.removeOne(item);
            }
        }

        if(!endItems.count()){
            setAddItemAtPoint(mouseEvent->scenePos());


            emit sigPopupMenu(addItemAtPoint);  //画线时弹出菜单


            QGraphicsScene::mouseReleaseEvent(mouseEvent);
            return;
        }



//        qDebug()<<startItems.count();
//        qDebug()<<endItems.count();
//        qDebug()<<startItems.first()->type();
//        qDebug()<<endItems.first()->type();
//        qDebug()<<(startItems.first() != endItems.first());

        if (startItems.count() > 0 && endItems.count() > 0 &&
            startItems.first()->type() == GY_DiagramItem::Type &&
            endItems.first()->type() == GY_DiagramItem::Type){
            if(startItems.first() != endItems.first()) {

                GY_DiagramItem *startItem = qgraphicsitem_cast<GY_DiagramItem *>(startItems.first());
                GY_DiagramItem *endItem = qgraphicsitem_cast<GY_DiagramItem *>(endItems.first());

                //线是否已连过
                bool addMore = true;  //
                bool sameStart=false;
                for(GY_Arrow * arrow : startItem->GetArrows()){
                    if(arrow->startPort() == line->startPort()){
                        sameStart = true;
    /*
                        if(line->GetLineType() == Arrow::proc){
                            //1个流程出口连线槽只能有1条连线
                            addMore = false;
                        }
    //*/
                        break;
                    }
                }

                /*line->endPort()此时未设置
                bool sameEnd=false;
                for(Arrow * arrow : endItem->GetArrows()){
                    if(arrow->endPort() == line->endPort()){
                        sameEnd = true;
                        if(line->GetLineType() == Arrow::data){
                            //1个参数入口连线槽只能有1条连线
                            addMore = false;
                        }
                        break;
                    }
                }
                */

                bool add = false;
                if(addMore //&& !(sameStart && sameEnd)
                        ){
                    switch (line->GetLineType()) {
                    case GY_Arrow::proc:
    /*                    //1个流程出口连线槽只能有1条连线
    //                    for(PortItem* port : startItem->GetPortsProcO()){
    //                        QPointF point = port->mapToScene(port->boundingRect().topLeft());
    //                        QRectF rect(point.x(),point.y(),port->boundingRect().width(),port->boundingRect().height());
    //                        if(rect.contains(line->line().p2())){
    //                            if(port->GetArrows().count()){
    //                                addMore = false;
    //                                break;
    //                            }
    //                        }
    //                    }
    //                    if(!addMore){break;}
    */

                        //TODO: 流程入口连线槽当已有1条连线时，如果其他item要连参数线过来则不能再连流程线。
                        //当前由生成python时处理调用流程先后。


                        for(GY_PortItem* port :endItem->GetPortsProcI()){
        //                    qDebug()<<port->mapToScene(port->boundingRect());
        //                    qDebug()<<line->line().p2();
                            QPointF point = port->mapToScene(port->boundingRect().topLeft());
                            QRectF rect(point.x(),point.y(),port->boundingRect().width(),port->boundingRect().height());
                            //qDebug()<<rect;
                            //if(port->mapToScene(port->boundingRect()).contains(line->line().p2())){  //mapToScene().contains()返回错误
                            if(rect.contains(line->line().p2())){

                                bool sameEnd=false;
                                for(GY_Arrow * arrow : endItem->GetArrows()){
                                    if(arrow->endPort() == port){
                                        sameEnd = true;
                                        break;
                                    }
                                }
                                if(sameStart && sameEnd){break;}


                                add = true;
                                line->SetEndPort(port);
                                //qDebug()<<(port == mPort);
                                line->startPort()->SetLineCount(1);
                                line->endPort()->SetLineCount(1);
                                startItem->addArrow(line);
                                endItem->addArrow(line);
                                line->setZValue(-1000.0);
                                //line->updatePosition();
                                port->SetColor(line->startPort()->GetColor());

                                break;
                            }
                        }
                        break;
                    case GY_Arrow::data:
                        for(GY_PortItem* port :endItem->GetPortsDataI()){
                            QPointF point = port->mapToScene(port->boundingRect().topLeft());
                            QRectF rect(point.x(),point.y(),port->boundingRect().width(),port->boundingRect().height());
                            if(rect.contains(line->line().p2())){
                                bool sameEnd=false;

                                for(GY_Arrow * arrow : endItem->GetArrows()){
                                    if(arrow->endPort() == port){
                                        sameEnd = true;
                                        //1个参数入口连线槽只能有1条连线
                                        addMore = false;
                                        break;
                                    }
                                }
                                if(!addMore){break;}
                                if(sameStart && sameEnd){break;}

                                add = true;
                                line->SetEndPort(port);
//                                port->setDescription("关联值");  //设计方案不使用此值
                                line->setZValue(-1000.0);
                                line->startPort()->SetLineCount(1);
                                line->endPort()->SetLineCount(1);
                                startItem->addArrow(line);
                                endItem->addArrow(line);
                                port->SetColor(line->startPort()->GetColor());

                                //DiagramItem::addArrow后执行
                                QString value;
                                for(GY_Arrow * arrow : endItem->GetArrows()){
                                    if(arrow->endPort() == port){
                                        //找到port值的来源
                                        GY_DiagramItem * item = (GY_DiagramItem *)arrow->startPort()->parentItem();
                                        value = item->getName() + "." + arrow->startPort()->getName();
                                        break;
                                    }
                                }
                                port->SetValue(value);  //参数连线后需要重置槽的参数值及更新参数面板值
                                break;
                            }
                        }
                        break;
                    default:
                        break;
                    }


                }

                if(!add){
                    removeItem(line);
                    delete line;
                }
            }
            else{  //line首尾相同
                removeItem(line);
                delete line;
            }


        }



        line = nullptr;

        setMode(MoveItem);
    }

    QGraphicsScene::mouseReleaseEvent(mouseEvent);
}

//! [14]
bool GY_DiagramScene::isItemChange(int type) const
{
    const QList<QGraphicsItem *> items = selectedItems();
    const auto cb = [type](const QGraphicsItem *item) { return item->type() == type; };
    return std::find_if(items.begin(), items.end(), cb) != items.end();
}

void GY_DiagramScene::setSelLine(GY_Arrow *value)
{
    selLine = value;
}

GY_Arrow *GY_DiagramScene::getSelLine() const
{
    return selLine;
}
//! [14]

void GY_DiagramScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event){
    //emit sigPopupMenu(event->screenPos());

    QGraphicsScene::contextMenuEvent(event);
}

void GY_DiagramScene::mousePress(QGraphicsSceneMouseEvent * mouseEvent){
    mousePressEvent(mouseEvent);
}

void GY_DiagramScene::setLineType(GY_Arrow::ArrowType type){
    //line->SetLineType(type);
    lineType = type;
}

void GY_DiagramScene::wheelEvent(QGraphicsSceneWheelEvent *event){



    QGraphicsScene::wheelEvent(event);
}

void GY_DiagramScene::keyPressEvent(QKeyEvent *event){



    QGraphicsScene::keyPressEvent(event);
}

void GY_DiagramScene::keyReleaseEvent(QKeyEvent *event){


    QGraphicsScene::keyReleaseEvent(event);
}

QGraphicsItem* GY_DiagramScene::SelectedItem(QPointF point){

    this->clearSelection();

    QTransform tran;
    QGraphicsItem* item = this->itemAt(point,tran);
    if(item){item->setSelected(true);}
    return item;

}

void GY_DiagramScene::SetSceneScale(int zoomIO){
    GY_GraphicsViewBP* view = (GY_GraphicsViewBP*)this->parent();
    QMatrix oldMatrix = view->matrix();
    view->resetMatrix();
    view->translate(oldMatrix.dx(), oldMatrix.dy());
    qreal newScale = GetScale();
    if(zoomIO > 0){  //放大
            qreal scales[]={0.5,0.75,1,1.25,1.5};
            for(qreal scale:scales){
                if(newScale < scale){
                    newScale = scale;
                    break;
                }
            }

    }else if(zoomIO < 0){
        qreal scales[]={1.5,1.25,1,0.75,0.5};
        for(qreal scale:scales){
            if(newScale > scale){
                newScale = scale;
                break;
            }
        }

    }
    else{
        newScale = 1;
    }
    //qDebug()<<newScale;

    view->scale(newScale, newScale);
    SaveScale(newScale);
}

void GY_DiagramScene::SaveScene(QString group, QString name, QJsonObject& schemeFile, QString filePath){
    if(group.isEmpty()||name.isEmpty()){return;}


    //新方案////////////////////////
    QJsonObject scheme;
    scheme["name"] = name;
    QJsonArray ItemArray;
    QJsonArray LineArray;
    for(QGraphicsItem* item:items()){
        if(item->type()==GY_DiagramItem::Type){
            GY_DiagramItem* it = ((GY_DiagramItem*)item);

            QJsonObject itemObj;
            itemObj["name"] =   it->GetName();
            itemObj["uuid"] =   it->GetUuid();
            itemObj["tips"] =   it->getTips();
            itemObj["x"] = it->pos().x();
            itemObj["y"] = it->pos().y();
            switch (it->diagramType()) {
            case GY_DiagramItem::Step:
                itemObj["type"] =   "Step";
                break;
            case GY_DiagramItem::StartEnd:
                itemObj["type"] =   "StartEnd";
                break;
            case GY_DiagramItem::Input:
                itemObj["type"] =   "Input";
                break;
            case GY_DiagramItem::Output:
                itemObj["type"] =   "Output";
                break;
            case GY_DiagramItem::Branch:
                itemObj["type"] =   "Branch";
                break;
            default:
                break;
            }

            QJsonArray PI;
            for(GY_PortItem* port:it->GetPortsProcI()){
                PI.append(port->GetName());
            }
            itemObj["PI"] = PI;

            QJsonArray PO;
            for(GY_PortItem* port:it->GetPortsProcO()){
                PO.append(port->GetName());
            }
            itemObj["PO"] = PO;

            QJsonArray DI;
            for(GY_PortItem* port:it->GetPortsDataI()){
                //DI.append(port->GetName());
                if(!port->GetName().isEmpty()){
                    QJsonObject portObj;
                    portObj["name"] =   port->GetName();
                    portObj["value"]=   port->GetValue();
                    portObj["signals"]=   port->getStrSignals();
//                        portObj["description"]=port->getDescription();  //设计方案不使用此值
                    DI.append(portObj);
                }
            }
            itemObj["DI"] = DI;

            QJsonArray DO;
            for(GY_PortItem* port:it->GetPortsDataO()){
                if(!port->GetName().isEmpty()){
                    //DO.append(port->GetName());
                    QJsonObject portObj;
                    portObj["name"] =   port->GetName();
                    portObj["value"]=   port->GetValue();
                    DO.append(portObj);
                }

            }
            itemObj["DO"] = DO;

            ItemArray.append(itemObj);

            for(GY_Arrow* line:it->GetArrows()){
                if(line->startPort()->parentItem()==it){
                    QJsonObject lineObj;
                    lineObj["from"] = it->GetUuid();
                    switch (line->GetLineType()) {
                    case GY_Arrow::proc :
                        lineObj["PO"] = line->startPort()->GetName();
                        lineObj["PI"] = line->endPort()->GetName();
                        break;
                    case GY_Arrow::data:
                        lineObj["DO"] = line->startPort()->GetName();
                        lineObj["DI"] = line->endPort()->GetName();
                            break;
                    default:
                        break;

                    }
                    lineObj["to"] = ((GY_DiagramItem*)line->endPort()->parentItem())->GetUuid();

                    LineArray.append(lineObj);
                }
            }

        }
    }
    scheme["item"] = ItemArray;
    scheme["line"] = LineArray;
    //新方案////////////////



    //数据比对
    QByteArray fileData;
//        QJsonParseError e;
    QJsonDocument doc;
//        QJsonObject obj;

//        QJsonArray arrayNew;
    QJsonObject groupNew;
    QJsonArray itemArrayNew;
    itemArrayNew.append(scheme);
    groupNew["group"] = group;
    groupNew["item"] = itemArrayNew;
//        arrayNew.append(groupNew);


    QFile file(filePath);
//        if(file.open(QIODevice::ReadOnly)){
//            fileData = file.readAll();
//            file.close();

//            doc = QJsonDocument::fromJson(fileData,&e);
//            if(e.error == QJsonParseError::NoError){
//                obj = doc.object();

            bool newApp = true;
            QJsonArray array = schemeFile["root"].toArray();
            for(int j = 0;j < array.size();++j){
                QJsonObject groupObj = array[j].toObject();
                if(groupObj["group"].toString()==group){
                    newApp = false;
                    QJsonArray itemArray = groupObj["item"].toArray();

                    bool newScheme = true;
                    int i = 0;
                    for(; i < itemArray.size(); ++i){
                        if(itemArray[i].toObject()["name"].toString()==name){
                            newScheme = false;
                            break;
                        }
                    }

                    if(newScheme){
                        itemArray.append(scheme);
                    }else{
                        itemArray.replace(i,scheme);
                    }
                    groupObj["item"] = itemArray;
                }
                array[j] = groupObj;
            }

            if(newApp){
                array.append(groupNew);
            }
            schemeFile["root"] = array;  //qDebug()<<array;
//            }
//            else{
//                obj["root"] = arrayNew;
//            }
//        }
//        else{
//            obj["root"] = arrayNew;
//        }

    doc.setObject(schemeFile);
    fileData = doc.toJson(QJsonDocument::Compact);
    QString jsonStr(fileData);
    if(file.open(QIODevice::WriteOnly | QIODevice::Text)){
        QTextStream in(&file);
        in.setCodec("UTF-8");  //处理中文问题
        in << jsonStr;
        file.close();
    }


//        SavePython(scheme, QJsonArray(), QStringList(), "test.py");  //存为python文件



}

void GY_DiagramScene::FindItemChain(QJsonArray items, QJsonArray lines, QJsonObject fromObj, QStringList& pyLines
                                 , QMap<QString, QMap<QString, QString>>& rets, int& indentTimes){
    QString from = fromObj["uuid"].toString();

    for(QJsonValue lv:lines){
        QJsonObject lo = lv.toObject();
        if(lo.contains("PI") && from==lo["from"].toString()){  //先找调用流程线

            FindItem(items, lines, fromObj, pyLines, rets, lo, indentTimes);
        }
        else
        if(lo.contains("DI") && from==lo["from"].toString()){  //找到参数连接线

            FindItem(items, lines, fromObj, pyLines, rets, lo, indentTimes);  //此处调用时branch空语句重复，已解决

        }
    }

}
void GY_DiagramScene::FindItem(QJsonArray items, QJsonArray lines, QJsonObject fromObj, QStringList& pyLines, QMap<QString, QMap<QString, QString>>& rets
                            , QJsonObject line, int& indentTimes){

    for(QJsonValue iv2:items){
        QJsonObject io2 = iv2.toObject();
        if(/*"End"!=io2["name"].toString() &&*/ line["to"].toString()==io2["uuid"].toString()){  //找到连线尾的item, 包含"End"
            //判断item "to"的类型
            if("Step"==io2["type"].toString()){
                //判断io2是否应该立即调用
                for(QJsonValue lv2:lines){
                    QJsonObject lo2 = lv2.toObject();
                    if(lo2.contains("DI") && line["to"].toString()==lo2["to"].toString() && fromObj["uuid"].toString() != lo2["from"].toString()){
                        //找到非from过来的参数连线，并且参数值还未计算
                        if(!rets.contains(lo2["from"].toString())){
                            return;
                        }
                    }
                }

                //判断io2是否已被调用过, 不做循环逻辑的生成
    //            qDebug()<<from << to << io2["name"];
                if(rets.contains(line["to"].toString())){
                    return;
                }


                //以下代码已确定要处理此item/////////////////////////
                QString strLine;  //用一行语句方便处理后面分支语句代码缩进
                //判断fromObj的类型
                if("Branch"==fromObj["type"].toString()){
                    //处理代码缩进
                    for(int i = indentTimes; i > 0; --i){
                        strLine.append("    ");  //缩进
                    }
                    indentTimes++;

                    //条件表达式
                    QString condition;
                    QJsonObject dobj = fromObj["DI"].toArray().first().toObject();
                    //先确定有无关联值
                    bool valueExists = false;
                    for(QJsonValue lv:lines){
                        QJsonObject lo = lv.toObject();
                        if(dobj["name"].toString()==lo["DI"].toString()
                                && fromObj["uuid"].toString()==lo["to"].toString()  //此处为fromObj["uuid"].toString()==lo["to"].toString()
                                ){  //找到branch的参数连线
                            if(rets.contains(lo["from"].toString())){
                                QMap<QString, QString> ret = rets.find(lo["from"].toString()).value();
                                if(!ret.find(lo["DO"].toString())->isEmpty()){
                                    condition = ret.find(lo["DO"].toString()).value();
                                    valueExists = true;
                                }
                            }
                            break;
                        }
                    }
                    if(!valueExists){
                        condition = dobj["value"].toString();  //输入了非真实可用的字符串值
                    }

                    QString strIfCond = "if " + condition;
                    strLine.append(strIfCond);
                    for(QString line : pyLines){
                        if(line.contains(strIfCond)){  //相同condition的分支语句
                            indentTimes = (line.indexOf(strIfCond) + 1) / 4;

                            strLine.clear();  //strLine重新处理
                            for(int i = indentTimes; i > 0; --i){
                                strLine.append("    ");  //缩进
                            }
                            indentTimes++;
                            strLine.append(strIfCond);

                            break;
                        }
                    }

                    if("True"==line["PO"].toString()){
                        strLine.append(" == True :\n");
                    }
                    else{
                        strLine.append(" == False :\n");
                    }

                    pyLines.append(strLine);
                }


                //处理代码缩进
                for(int i = indentTimes; i > 0; --i){
                    pyLines.append("    ");  //缩进
                }

                for(int i = 0; i <io2["DO"].toArray().count(); ++i){
                    QJsonObject dobj = io2["DO"].toArray()[i].toObject();
                    if(i){pyLines.append(", ");}
                    QMap<QString, QString> newName;
                    QString name = QString("%1%2").arg(dobj["name"].toString()).arg(qrand() % 1000);
                    newName.insert(dobj["name"].toString(),name);
                    rets.insert(line["to"].toString(), newName);
                    pyLines.append(name);

                }
                pyLines.append(" = ");

                pyLines.append(io2["name"].toString());
                pyLines.append("(");
                for(int i = 0; i <io2["DI"].toArray().count(); ++i){
                    if(i){pyLines.append(", ");}
                    QJsonObject dobj = io2["DI"].toArray()[i].toObject();
                    //先确定有无关联值
                    bool valueExists = false;
                    for(QJsonValue lv:lines){
                        QJsonObject lo = lv.toObject();
                        if(dobj["name"].toString()==lo["DI"].toString() && line["to"].toString()==lo["to"].toString()){  //找到item的参数连线
                            if(rets.contains(lo["from"].toString())){
                                QMap<QString, QString> ret = rets.find(lo["from"].toString()).value();
                                if(!ret.find(lo["DO"].toString())->isEmpty()){
                                    valueExists = true;
                                    pyLines.append(ret.find(lo["DO"].toString()).value());  //关联值
                                }
                            }

                            break;
                        }
                    }

                    if(!valueExists){
                        pyLines.append(dobj["value"].toString());  //输入了非真实可用的字符串值
                    }
                }
                pyLines.append(")\n");

                FindItemChain(items, lines, io2, pyLines, rets, indentTimes);
                break;

            }
            else if("Branch"==io2["type"].toString()){

                FindItemChain(items, lines, io2, pyLines, rets, indentTimes);
                break;
            }
/*            else if("Output"==io2["type"].toString()){
                for(int i = 0; i <io2["DI"].toArray().count(); ++i){
                    QJsonObject dobj = io2["DI"].toArray()[i].toObject();
//                    if(dobj["value"].toString().isEmpty()){  //输入了非真实可用的字符串值
                        for(QJsonValue lv:lines){
                            QJsonObject lo = lv.toObject();
                            if(dobj["name"].toString()==lo["DI"].toString() && line["to"].toString()==lo["to"].toString()){  //找到item的参数连线
                                if(rets.contains(lo["from"].toString())){
                                    QMap<QString, QString> ret = rets.find(lo["from"].toString()).value();
                                    if(!ret.find(lo["DO"].toString())->isEmpty()){
                                        QString line;

                                        //处理代码缩进
                                        for(int i = indentTimes; i > 0; --i){
                                            line.append("    ");  //缩进
                                        }
                                        QString retLast = ret.find(lo["DO"].toString()).value();
                                        //返回值  //流程线和参数线重复执行
                                        line.append("return " + retLast + "\n");

                                        //判断io2是否已被调用过
                                        if(pyLines.last() != line){
                                            pyLines.append(line);
                                        }
                                    }
                                }

                                break;
                            }
                        }
//                    }
                    break;  //只有一个返回值
                }

            }
//*/
            else if("End" == io2["name"].toString()){  //"End"图元 处理返回值
                if("Step"==fromObj["type"].toString()){
                    if(rets.contains(fromObj["uuid"].toString())){
                        QMap<QString, QString> ret = rets.find(fromObj["uuid"].toString()).value();
                        if(ret.size()){  //有返回值
                            QString line;

                            //处理代码缩进
                            for(int i = indentTimes; i > 0; --i){
                                line.append("    ");  //缩进
                            }
                            QString retLast = ret.find(ret.firstKey()).value();  //只有一个返回值
                            //返回值  //流程线和参数线重复执行
                            line.append("return " + retLast + "\n");

                            //判断io2是否已被调用过
                            if(pyLines.last() != line){
                                pyLines.append(line);
                            }
                        }
                    }
                }
            }
        }

    }
}

void GY_DiagramScene::SavePython(QJsonObject scheme, QJsonArray sigVars, QStringList varNames, QString fileName){


    //sigVars存为json文件
    //sigVars中的顺序需与传参顺序一致
    if(!sigVars.isEmpty()){
        QJsonDocument doc;
        doc.setArray(sigVars);
        QByteArray fileData = doc.toJson(QJsonDocument::Compact);
        QString jsonStr(fileData);
        QString fileNameNoSuffix = fileName;
        fileNameNoSuffix.chop(3);
        QFile file(QString("%1.json").arg(fileNameNoSuffix));
        if(file.open(QIODevice::WriteOnly | QIODevice::Text)){
            QTextStream in(&file);
            in.setCodec("UTF-8");  //处理中文问题
            in << jsonStr;
            file.close();
        }
    }


    //
    QStringList pyLines;  //最终转换为pyCode
    QString pyCode;
    QJsonArray items = scheme["item"].toArray();
    QJsonArray lines = scheme["line"].toArray();

    //py文件头///////


    //import包
    QStringList packages;

    packages = GY_PopupMenu::getPackages();


    for(QString package : packages){
        pyLines.append("import " + package + "\n");
    }
    pyLines.append("\n");
    //////////////////

    //函数设参
    if(!sigVars.isEmpty()){
        pyLines.append("def Scheme(time");
        for(QJsonValue pv : sigVars){
            pyLines.append(",");
            pyLines.append(pv.toObject()["variant"].toString());
        }
    }
    else{
        pyLines.append("def Scheme(");
        for(int i = 0; i < varNames.size(); ++i){
            if(i){
                pyLines.append(",");
            }
            pyLines.append(varNames[i]);
        }
    }
    pyLines.append("):\n");


    //py代码体
    for(QJsonValue iv:items){
        QJsonObject io = iv.toObject();
        if("Start"==io["name"].toString()){
            QMap<QString, QMap<QString, QString>> rets;  //保存返回值的变量名称
            int indentTimes = 1;
            FindItemChain(items, lines, io, pyLines, rets, indentTimes);
            break;
        }
    }


    //转换为pyCode
    for(QString line: pyLines){
        pyCode.append(line);
    }

//    qDebug()<<pyCode;

    QFile pyFile(fileName);
    if(pyFile.open(QIODevice::WriteOnly | QIODevice::Text)){
        QTextStream in(&pyFile);
        in.setCodec("UTF-8");  //处理中文问题
        in << pyCode;
        pyFile.close();
    }
}
